﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;

namespace CubeCalculations
{
   public class ThreadedEvolutionaryCubexWorker
   {
      #region Delegates

      public delegate bool RequestMovesEventHandler(ThreadedEvolutionaryCubexWorker Sender, out List<int> SolutionList);

      public delegate void SetSolutionEventHandler(
         ThreadedEvolutionaryCubexWorker Sender, List<int> Solution, int SolutionLength, float KukaMoves);

      #endregion

      private readonly Cubex BaseCube;

      private readonly AutoResetEvent resetEvent = new AutoResetEvent(false);
      private readonly MovementRating MovementRating = new MovementRating();

      public ThreadedEvolutionaryCubexWorker()
      {
         BaseCube = new Cubex();
      }

      public Cubex Cube
      {
         get { return BaseCube; }
         set { value.CopyTo(BaseCube); }
      }

      public event RequestMovesEventHandler OnRequestMoves;
      public event SetSolutionEventHandler OnSetSolution;

      public void Continue()
      {
         resetEvent.Set();
      }


      public List<CubeMoves> SolveCube()
      {
         BaseCube.SolveCube();
         return BaseCube.Solution();
      }

      public void EvaluateSolutions()
      {
         List<int> solutionList;
         var solutionCube = new Cubex();
         while (true)
         {
            while (!OnRequestMoves(this, out solutionList))
            {
               resetEvent.WaitOne();
            }
            BaseCube.CopyTo(solutionCube);

            ExecuteCurrentSolution(solutionList, solutionCube);
            float KukaMoves = 0;
            int SolLen = SolveCube(solutionCube, /*solutionList.Count + PreSolutionList.Count,*/ out KukaMoves);
            OnSetSolution(this, solutionList, SolLen, KukaMoves);
         }
      }
      List<int> PreSolutionList = new List<int>();
      private string BaseSolutionString ="";
      public void PrepareCube(Cubex Cube, List<int> PreSolution)
      {
         lock (this)
         {
            //PreSolutionList.Clear();
            //PreSolutionList.AddRange(PreSolution);
            Cube.CopyTo(BaseCube);

            BaseSolutionString = BaseCube.Evaluate(PreSolution.ToArray());

         }
      }


      private int SolveCube(Cubex Cube,/* int BaseSteps,*/ out float KukaMovements)
      {
         Cube.SolveCube();
         List<CubeMoves> MoveSolution = Cubex.Solution(BaseSolutionString + CurrentSolutionString + Cube.solution);

         KukaMovements = MovementRating.RateSolution(MoveSolution);
         return MoveSolution.Count /*+ BaseSteps*/;
      }

      private string CurrentSolutionString = "";
      private void ExecuteCurrentSolution(List<int> Moves, Cubex cubex)
      {
         CurrentSolutionString = cubex.Evaluate(Moves.ToArray());
      }
   }
}